package com.iflytek.autoCompareTool.service;

import com.iflytek.autoCompareTool.common.Config;
import com.iflytek.autoCompareTool.common.DBManager;
import com.iflytek.autoCompareTool.common.TaskManager;
import com.iflytek.autoCompareTool.model.InputInfo;
import com.iflytek.autoCompareTool.model.OutputData;
import com.iflytek.autoCompareTool.model.TestData;
import com.iflytek.autoCompareTool.model.TestSet;
import com.iflytek.autoCompareTool.utils.FastdfsUtil;
import com.iflytek.autoCompareTool.utils.FileUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

/**
 * @author llchen12
 * @date 2018/6/5
 */
public class Processor implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(Processor.class);


    private TestData testData;


    public Processor(TestData testData) {
        Assert.notNull(testData, "测试数据不能为空");
        this.testData = testData;
    }

    @Override
    public void run() {
        logger.debug("Processor start.....");
        long start = System.currentTimeMillis();

        //设置该任务保存路径
        String resultDir = Config.RESULT_DIR;
        if (!resultDir.endsWith("/")) {
            resultDir += "/";
        }
        String path = resultDir + start;

        //获取该任务对应的所有测试集及相关信息
        Map<String, List<TestSet>> testSetMap = testData.getTestSetMap();
        InputInfo inputInfo = testData.getInputInfo();
        Integer id = inputInfo.getId();


        int testSetSize = testData.size();

        //如果测试集为空，健壮性考虑，一般不会出现
        if (testSetSize == 0) {
            TaskManager.removeTask(id);
            return;
        }

        //***************测试集执行准备*******************

        //启动线程监视当前任务是否手动停止
        Checker checkProgress = Checker.getInstance();
        checkProgress.check(id);

        logger.debug(id + "号任务执行的测试集大小：" + testSetSize);

        //保存不一致，如果不对比将不产生不一致部分
        OutputData diffPart = null;
        if (inputInfo.getSingleEnv() == 0) {
            diffPart = new OutputData(path + "/不一致部分.xlsx", inputInfo);
        }

        int preNum = 0;

        //***************按照FileName分类执行测试集***************
        for (Map.Entry<String, List<TestSet>> entry : testSetMap.entrySet()) {
            String fileName = entry.getKey();
            List<TestSet> testSetList = entry.getValue();
            if (testSetList.isEmpty()) {
                continue;
            }

            //保存单个FileName的结果
            OutputData result;
            if (fileName.endsWith("xls")) {
                fileName = fileName.replace("xls", "xlsx");
            }
            result = new OutputData(path + "/" + fileName, inputInfo);

            //****按照uid进行分组，并确定多线程数量****
            Map<String, List<TestSet>> mapGroupByUID = new LinkedHashMap<>();
            for (TestSet testSet : testSetList) {
                String uid = testSet.getUid();
                if (mapGroupByUID.containsKey(uid)) {
                    mapGroupByUID.get(uid).add(testSet);
                } else {
                    List<TestSet> list = new ArrayList<>();
                    list.add(testSet);
                    mapGroupByUID.put(uid, list);
                }
            }

            CountDownLatch countDownLatch = new CountDownLatch(mapGroupByUID.size());

            logger.debug(id + "号任务" + fileName + "执行的测试集大小：" + testSetSize);

            //****************************开启多线程执行测试************************
            ExecutorService workThreadPool = Executor.getInstance().getWorkThreadPool();
            for (Map.Entry<String, List<TestSet>> e : mapGroupByUID.entrySet()) {
                Worker worker = new Worker(id, inputInfo, countDownLatch, diffPart, result, e.getValue(), preNum);
                workThreadPool.execute(worker);
            }
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                logger.error("countDownLatch异常", e);
            }

            //**如果任务被手动停止，不保存并跳出任务**/
            if (TaskManager.isCancel(id)) {
                result.close();
                logger.debug(fileName + "任务被手动停止，不保存并跳出任务");
                break;
            }

            //**保存该usrid结果**/
            result.save();
            preNum = preNum + testSetSize;
            logger.debug(fileName + "执行完毕");
        }

        //**如果任务被手动停止，不保存并跳出任务**/
        if (TaskManager.isCancel(id)) {
            logger.info(id + "号任务停止成功！");
            //** 移除该任务 **/
            TaskManager.removeTask(id);
            logger.debug("移除任务" + id);
            if (diffPart != null) {
                diffPart.close();
            }
        }

        //**只有对比时，才产生不一致结果**/
        if (inputInfo.getSingleEnv() == 0) {
            try {
                diffPart.saveDiff();
            } catch (Exception e) {
                logger.debug(id + "保存不一致结果出错", e);
            } finally {
                diffPart.close();
            }
        }

        logger.debug("全部执行完毕,开始压缩....");
        long finishTime = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmm");
        String fname = sdf.format(finishTime) + "_" + id;
        try {
            if (FileUtil.fileToZip(path, resultDir, fname)) {
                logger.debug("{} 压缩完毕，准备发送邮件！", fname);
            }
        } catch (Exception e) {
            logger.error("压缩文件失败：", e);
        }

        long totalTime = (finishTime - start) / 1000;

        //**  执行完成更新数据库 **/
        String baseUrl = Config.DOWNLOAD_URL.endsWith("/") ? Config.DOWNLOAD_URL.substring(0,Config.DOWNLOAD_URL.length()-1) : Config.DOWNLOAD_URL;
        String zipFile = resultDir + fname + ".zip";
        String remoteFile=FastdfsUtil.upload(zipFile);
        //更新映射表
        updateFastdfsFileMapping(remoteFile,zipFile,fname);
        String downloadUrl = baseUrl +fname;

        System.out.println("downloadUrl: " + downloadUrl);
        updateDatabase(totalTime, downloadUrl, id);
        //** 移除执行完的测试集 **/
        TaskManager.removeTask(id);
        logger.debug("移除执行完的任务:{}", id);

        //删除temp文件
        FileUtil.delete(path,zipFile);

        //TODO:发送邮件

    }

    /**
     * 更新数据库,目前根据id的正负确定数据库.
     **/
    public void updateDatabase(long speed, String url, Integer id) {
        String sql = "update tool_testupload set speed=?,progress=100,url=? " +
                "where id=?";

        QueryRunner qr = DBManager.getInstance().getAiuiManagerQr();
        try {
            qr.update(sql, speed, url, Math.abs(id));
        } catch (SQLException e) {
            logger.error("更新数据库异常", e);
        }

    }


    private void updateFastdfsFileMapping(String remoteFile,String localFile,String fileName){

        String sql="insert into fastdfs_file_mapping(remoteFile,localFile,extName,business,platIndex,status,createTime,updateTime) " +
                "values(?,?,'zip','auto-test-result',?,1,?,?);";

        QueryRunner qr = DBManager.getInstance().getAiuiManagerQr();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        String time = sdf.format(new Date());
        try {
            qr.insert(sql, rs -> null,remoteFile,localFile,fileName,time,time);
        } catch (SQLException e) {
            logger.error("更新fastdfs_file_mapping表异常", e);
        }
    }
}
